package com.openlogic.common.logic.run;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.text.StringEscapeUtils;
import org.noear.solon.annotation.Component;
import org.noear.solon.core.event.AppBeanLoadEndEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import com.openlogic.common.core.utils.DateUtils;
import com.openlogic.common.logic.constants.RuleConstants;
import com.openlogic.common.logic.node.enums.NodeExecEnums;
import com.openlogic.common.logic.node.factory.NodeExecFactory;
import com.openlogic.common.logic.utils.NumericRegxUtils;
import com.openlogic.common.logic.utils.StackExceptionUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

/**
* @ClassName: ExecCrossMatrixNodeHandler
* @Description: 交叉矩阵节点运行执行器
* @author weiyongpeng
* @date 2024年7月17日 上午9:12:36
 */
@Component
public class ExecCrossMatrixNodeHandler extends ExecRuleHandler{
	
	private static final Logger logger = LoggerFactory.getLogger(ExecCrossMatrixNodeHandler.class);

	@Override
	public JSONObject typeRun(JSONArray resultArray1,JSONArray nodeArray,JSONArray lineArray,JSONObject inputjson,JSONArray areaArray,String areaFirst,String ruleId,StringBuffer reason,Map<String,Object> map) {
		JSONObject reJson = new JSONObject();
		logger.info("CrossMartixNode Begin Run Starting...");
		// 默认节点解析后的数据
		logger.info("typeRun=====" +  resultArray1.toString());
		reJson = recRunForNode(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,reason,map);	
		return reJson;
	}

	/**
	* 描述：迭代节点执行
	* @Title: recRunForDefault
	* @param resultArray1
	* @param nodeArray
	* @param lineArray
	* @param inputjson
	* @param areaArray
	* @param areaFirst
	* @param ruleId
	* @param reason
	* @param map
	* @return
	* @author weiyongpeng
	* @date  2024年7月17日 上午10:29:23
	 */
	@SuppressWarnings("rawtypes")
	@Override
	protected JSONObject recRunForNode(JSONArray resultArray1, JSONArray nodeArray, JSONArray lineArray,
			JSONObject inputjson, JSONArray areaArray, String areaFirst, String ruleId, StringBuffer reason,
			Map<String, Object> map) {
		Map<Object,Object> inParam = new HashMap<>();
		Map<Object,Object> outParam = new HashMap<>();
	    for (Object ijo : inputjson.entrySet()){
	    	if(!((Map.Entry)ijo).getKey().toString().equals("everyNodeList") && !((Map.Entry)ijo).getKey().toString().equals("areaInfo") ) {
	    		inParam.put(((Map.Entry)ijo).getKey().toString().replaceAll("\"", ""), ((Map.Entry)ijo).getValue().toString().replaceAll("\"", ""));
	    	}
	    }
		// 开始执行时间
		Date startDate = DateUtils.getNowDate();
		String startExecuateTime = DateUtils.formatDate(startDate, DateUtils.YYYY_MM_DD_HH_MM_SS);
		// 异常信息
		String errorMsg = "";
		// 流程执行结束的json对象
		JSONObject reJson = new JSONObject();
		// 发生异常的时候返回的json对象
		JSONObject errorJson = new JSONObject();
		// 下一个可执行节点的json对象
		JSONObject nextResult = new JSONObject();
		
		try {
			//那么
			String successString = ((JSONObject)resultArray1.get(3)).get("success").toString();
			successString = StringEscapeUtils.unescapeXml(successString);

			JSONObject tmpObject = JSONObject.fromObject(successString);
			String str = tmpObject.get("cMatrData").toString();
			str = StringEscapeUtils.unescapeXml(str);

			String resultStr = runAndGetResultForCMatr(str,inputjson.toString(),reason);
			
			inputjson = JSONObject.fromObject(resultStr);
		} catch (Exception e) {
			errorMsg = StackExceptionUtils.getExceptionType(e).toString();
			logger.error("异常信息:{}",e.getMessage());
		}
		
		if (errorMsg == null || errorMsg.equals("")) {
			for (Object ijo : inputjson.entrySet()){
		    	if(!((Map.Entry)ijo).getKey().toString().equals("everyNodeList") && !((Map.Entry)ijo).getKey().toString().equals("areaInfo") ) {
		    		outParam.put(((Map.Entry)ijo).getKey().toString().replaceAll("\"", ""), ((Map.Entry)ijo).getValue().toString().replaceAll("\"", ""));
		    	}
		    }
			reJson = inputjson;
			if(resultArray1.get(2).equals("area")) {
				if(areaFirst.equals("")) {//判断是否是循环的第一个 节点
					areaFirst = resultArray1.getString(0);
					reJson.put("areaFirst", areaFirst);
				}
			}
			nextResult = runNextNode(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,0,reason,map,startDate,inParam,outParam);
			if(!nextResult.toString().equals("{}")) {
				return nextResult;
			}
		}else {
			Map<Object,Object> errorMap = new HashMap<>();
			errorMap.put("msg", errorMsg);
			errorJson = JSONObject.fromObject(errorMap);
			// 执行异常信息
			nextResult = runNextNodeThrow(resultArray1,nodeArray,lineArray,inputjson,areaArray,areaFirst,ruleId,0,reason,map,startDate,inParam,errorJson);
			if(!nextResult.toString().equals("{}")) {
				return nextResult;
			}
		}
		
		// 结束执行时间
		Date endDate = DateUtils.getNowDate();
		String endExecuateTime = DateUtils.formatDate(endDate, DateUtils.YYYY_MM_DD_HH_MM_SS);
		reJson.put("startExecTime", startExecuateTime);
		reJson.put("endExecTime", endExecuateTime);
		reJson.put("execTotalTimeMills", "耗时: "+(endDate.getTime() - startDate.getTime())+" 毫秒");
		reJson.put("execStatus", RuleConstants.NODE_EXEC_SUCCESS);
		return reJson;
	}
	
	@SuppressWarnings("unchecked")
	private String runAndGetResultForCMatr(String str,String parmInfo, StringBuffer reason) throws Exception{
		//新添加代码
		List<Double>  list =new ArrayList<Double>();
		String str2 =null;
		
		//一下为之前代码
		JSONArray newDataArray = new JSONArray();
		JSONArray newDataArrayJson = new JSONArray();
		JSONArray trueArrayJson = new JSONArray();
		newDataArray = getDataArray(str);
		// 20240805-modifyby-weiyongpeng-调整新的交叉矩阵数据格式，不需要保留样式
		// logger.info("str=={}",str);
		// logger.info("parmInfo=={}",parmInfo);
		String newDataArrayStr = newDataArray.toString();
		JSONObject inputjson = JSONObject.fromObject(parmInfo);
		inputjson = sortJson(inputjson);
		
		newDataArrayJson = JSONArray.fromObject(newDataArrayStr);
		trueArrayJson = getTrueJsonArray(newDataArrayJson,inputjson);
		Map<String, Object> env = inputjson;
		for(int i=0;i<trueArrayJson.size();i++) {
			JSONArray dataArray = new JSONArray();
			dataArray = trueArrayJson.getJSONArray(i); 
			
			for(int j=0;j<dataArray.size();j++) {
				JSONObject data = dataArray.getJSONObject(j);
				//  新添加代码2024-09-09
				if((boolean)data.get("isTrue")&& !data.get("type").equals("4") && !data.get("type").equals("1") && !data.get("quanzhong").equals("")) {
					list.add(Double.valueOf((String)data.get("quanzhong")));
					reason.append("满足："+data.get("reason").toString().replaceAll("&&", "并且").replaceAll("\\|\\|", "或者")).append(",");
				}
				//  以下为之前代码
				if((boolean)data.get("isTrue")&&data.get("type").equals("4")) {
					String[] succlist = data.get("formula").toString().split("&&");
					for(int k=0,succlength=succlist.length;k<succlength;k++) {
						String[] succlist1 = succlist[k].split("=");
						
						for(int h=0,succlength1=succlist1.length;h<succlength1;h++) {
							if(h==0) {
								//执行自定义函数
								if(succlist1[1].contains("(")||succlist1[1].contains("+")||succlist1[1].contains("-")||succlist1[1].contains("*")||succlist1[1].contains("/")) {
									//遍历替换success中的变量
									String[] temp = succlist1[1].split("\\^");
									String tempStr = "";
									for(int o =0;o<temp.length;o++) {
										if(temp[o].indexOf("com")!=-1) {
											tempStr+=temp[o];
										}else {
											Iterator<String> it1 = inputjson.keys(); 
											while(it1.hasNext()){
												// 获得key
												String key = it1.next(); 
												//特别注意数字不带单引号，字符串带单引号
												temp[o] = temp[o].replaceAll(key, NumericRegxUtils.isNumber(inputjson.getString(key))?inputjson.getString(key):"'"+inputjson.getString(key)+"'");
											}
											tempStr+=temp[o];
										}
									}
									Expression compile = AviatorEvaluator.compile(tempStr, true);
									Object res = compile.execute(env);
									// 赋值
									inputjson.put(succlist1[0], res);
								}else {
									//遍历替换success中的变量
									Iterator<String> it1 = inputjson.keys(); 
									while(it1.hasNext()){
										// 获得key
										String key = it1.next(); 
										succlist1[1] = succlist1[1].replaceAll(key, NumericRegxUtils.isNumber(inputjson.getString(key))?inputjson.getString(key):"'"+inputjson.getString(key)+"'");
									}
									//赋值
									inputjson.put(succlist1[0], succlist1[1]);
								}
								// 新添加
								str2=succlist1[0];
							}
						}
					}
				}
			}
		}
		// logger.info("runAndGetResultForCMatr()返回的数据为=={}", inputjson.toString());
		// logger.info("添加的list 的值=={}", list.toString());
		Object aObj = inputjson.get(str2);
		Double db1 = null ;
		try {
			if(aObj != null && Double.valueOf(aObj.toString()) instanceof Double) {
				db1=sum(list)/100 * Double.valueOf(aObj.toString());
				BigDecimal b= new BigDecimal(db1/list.size());
				String value=Double.toString(b.setScale(2, RoundingMode.HALF_UP).doubleValue());
				inputjson.put(str2,value);
			}
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		return inputjson.toString();
	}
	
	//  新增加求和方法
	private static Double sum(List <Double> list) {
		Double sum = (double) 0;
        for (Double i : list) {
            sum += i;
        }
        return sum;
    }
	
	@SuppressWarnings("unchecked")
	private JSONArray getTrueJsonArray(JSONArray newDataArrayJson, JSONObject inputjson) {
		Map<String, Object> env = inputjson;
		for(int i=0;i<newDataArrayJson.size();i++){
			JSONArray dataArrayNew = new JSONArray();
			dataArrayNew = newDataArrayJson.getJSONArray(i); 
			for(int j=0;j<dataArrayNew.size();j++){
				JSONObject data = dataArrayNew.getJSONObject(j);
				if((boolean)data.get("isTrue")) {
					if(data.get("type").equals("2")) {
						boolean result=true;
						//执行判断
					    try {
					    	if (data.get("formula").toString().contains("@")) {
								Set<String> sqlVars = extractStrings(data.get("formula").toString());
//								Map<String,Object> map = new HashMap<>();
								String formula = data.get("formula").toString();
								for (String sqlVar : sqlVars) {
									if (sqlVar.split("\\.").length >= 2) {
										// sql参数某个字段
										formula = selectRuleSqlParamResByAviator(inputjson, sqlVar, data, true, env);
									}else {
										// 单纯的sql参数
										formula = selectRuleSqlParamResByAviator(inputjson, sqlVar, data, false, env);
									}
								}
								Expression compile = AviatorEvaluator.compile(formula.replaceAll("\\@", ""),true);
								result = (Boolean)compile.execute(env);
							}else {
								result = (Boolean) AviatorEvaluator.execute(data.get("formula").toString(), env, true);
							}
						} catch (Exception e) {
							logger.error("异常信息:{}",e.getMessage());
						}
					    if(!result) {
					    	for(int k=0;k<newDataArrayJson.size();k++) {
					    		JSONArray dataArrayNew1 = new JSONArray();
					    		dataArrayNew1 = newDataArrayJson.getJSONArray(k); 
					    		JSONObject data1 = dataArrayNew1.getJSONObject(j);
					    		data1.put("isTrue", false);
					    	}
					    }
					}else if(data.get("type").equals("3")) {
						boolean result=true;
						//执行判断
					    try {
					    	if (data.get("formula").toString().contains("@")) {
								Set<String> sqlVars = extractStrings(data.get("formula").toString());
//								Map<String,Object> map = new HashMap<>();
								String formula = data.get("formula").toString();
								for (String sqlVar : sqlVars) {
									if (sqlVar.split("\\.").length >= 2) {
										// sql参数某个字段
										formula = selectRuleSqlParamResByAviator(inputjson, sqlVar, data, true, env);
									}else {
										// 单纯的sql参数
										formula = selectRuleSqlParamResByAviator(inputjson, sqlVar, data, false, env);
									}
								}
								Expression compile = AviatorEvaluator.compile(formula.replaceAll("\\@", ""),true);
								result = (Boolean)compile.execute(env);
							}else {
								result = (Boolean) AviatorEvaluator.execute(data.get("formula").toString(), env, true);
							}
						} catch (Exception e) {
							e.printStackTrace();
						}
					    if(!result) {
					    	JSONArray dataArrayNew2 = new JSONArray();
				    		dataArrayNew2 = newDataArrayJson.getJSONArray(i); 
					    	for(int h=0;h<dataArrayNew2.size();h++) {
					    		JSONObject data2 = dataArrayNew2.getJSONObject(h);
					    		data2.put("isTrue", false);
					    	}
					    }
					}
				}
			}
		}
		return newDataArrayJson;
	}
	
	public JSONArray getDataArray(String str) {
		JSONObject strJson = JSONObject.fromObject(str);
		JSONArray dataArray = new JSONArray();
		dataArray = JSONArray.fromObject(strJson.get("data"));
		JSONArray newDataArray = new JSONArray();
		int rowNum = dataArray.size(); 
		for(int i=0;i<rowNum;i++) {
			int colNum = dataArray.getJSONArray(rowNum-1).size();
			JSONArray newDataArr = new JSONArray();
			for(int j=0;j<colNum;j++) {
				JSONObject data = new JSONObject();  
				newDataArr.add(data);
			}
			newDataArray.add(newDataArr);
		}
		int type1_num=0;//type1 列数
		for(int i=0;i<dataArray.size();i++){
			JSONArray dataArrayNew = new JSONArray();
			dataArrayNew = dataArray.getJSONArray(i); 
			int lineNum=0;
			for(int j=0;j<dataArrayNew.size();j++){
				JSONObject data = dataArrayNew.getJSONObject(j); 
				if(i==0&&j==0) {
					type1_num = Integer.parseInt(data.get("colspan").toString());
				}
				if(j==0) {
					if(data.get("type").equals("2")||data.get("type").equals("1")) {
						lineNum=type1_num;
					}else {
						lineNum=0;
					}
				}
				if(data.get("type").equals("3") && data.get("isHidden") != null &&(boolean)data.get("isHidden")==true) {
				}else if(!data.get("type").equals("4")){
					String formula = "";
					String showValue = "";
					formula = getFormula(data);
					showValue = getShowValue(data);
					int col = Integer.parseInt(data.get("colspan").toString());
					int row = Integer.parseInt(data.get("rowspan").toString());
					if(data.get("type").equals("1")) {
						for(int k=0;k<row;k++) {
							JSONArray dataArr = newDataArray.getJSONArray(k);
							for(int h=0;h<col;h++) {
								JSONObject d = dataArr.getJSONObject(h);
								d.put("type", data.get("type")) ;
								d.put("isTrue", true) ;
								d.put("quanzhong", "") ;
								d.put("formula",formula);
								d.put("reason", showValue);
							}
						}
					}else if(data.get("type").equals("2")){
						JSONArray dataArr = newDataArray.getJSONArray(i);
						for(int h=0;h<col;h++) {
							JSONObject d = dataArr.getJSONObject(h+lineNum);
							d.put("type", data.get("type")) ;
							d.put("isTrue", true) ;
							d.put("quanzhong", data.get("quanzhong")) ;
							d.put("formula",formula);
							d.put("reason", showValue);
						}			
						lineNum+=col;
					}else if(data.get("type").equals("3")){
						for(int k=0;k<row;k++) {
							JSONArray dataArr = newDataArray.getJSONArray(i+k);
							JSONObject d = dataArr.getJSONObject(j);
							d.put("type", data.get("type")) ;
							d.put("isTrue", true) ;
							d.put("quanzhong", data.get("quanzhong")) ;
							d.put("formula",formula);
							d.put("reason", showValue);
						}
					}else {
						JSONArray dataArr = newDataArray.getJSONArray(i);
						JSONObject d = dataArr.getJSONObject(j);
						d.put("type", data.get("type")) ;
						d.put("isTrue", true) ;
						d.put("quanzhong", data.get("quanzhong")) ;
						d.put("formula",formula);
						d.put("reason", showValue);
					}
				} else if (data.get("type").equals("4")) {
					String formula = "";
					formula = getFormula(data);
					JSONArray dataArr = newDataArray.getJSONArray(i);
					JSONObject d = dataArr.getJSONObject(j);
					d.put("type", data.get("type"));
					d.put("isTrue", true);
					d.put("quanzhong", data.get("quanzhong"));
					d.put("formula", formula);
				}
			}
		}
		return newDataArray;
	}
	
	private String getFormula(JSONObject data) {
		String type = data.get("type").toString();
		String formula="";
		if(type.equals("1")) {
			formula = "";
		}else if(type.equals("4")) {
			String hiddenValue = data.get("formula").toString();
			if(hiddenValue!="") {
				formula = hiddenValue;
			}
		}else {
			String hiddenValue = data.get("formula").toString();
			if(!"".equals(hiddenValue)) {
				formula = hiddenValue;
			}else {
				formula="1==1";
			}
			
		}
		return formula;
	}
	
	private String getShowValue(JSONObject data) {
		String type = data.get("type").toString();
		String judgeValue="";
		if(type.equals("2") || type.equals("3")) {
			String showValue = data.get("showValue").toString();
			if(!"".equals(showValue)) {
				judgeValue = showValue;
			}else {
				judgeValue="";
			}
		}
		return judgeValue;
	}
	
	@Override
	public void onEvent(AppBeanLoadEndEvent event) throws Throwable {
		NodeExecFactory.register(NodeExecEnums.CMATR_NODE.getCode(), this);
	}

}
